package com.example.controller;

import com.example.Utils.FileNameEncodingUtils;
import com.example.Utils.InputStreamUtils;
import com.example.constant.FileConstant;
import com.example.entity.FilesEntity;
import com.example.enums.ErrorCode;
import com.example.exception.SelfRuntimeException;
import com.example.model.dto.GetFileInfo;
import com.example.model.response.RestResponse;
import com.example.model.response.RestResponseEntity;
import com.example.model.response.ServiceResult;
import com.example.service.FilesService;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("api/file")
public class FileDownloadController {

    @Autowired
    private FilesService filesService;


    /**
     * 获取文件信息列表（带分页）
     *
     * @param pageNo   当前页
     * @param pageSize 分页大小
     * @return 返回结果对象
     */
    @GetMapping("/list")
    public RestResponse<List<GetFileInfo>> getFileList(@RequestParam Integer pageNo, @RequestParam Integer pageSize) throws IOException {
        ServiceResult<List<GetFileInfo>> fileInfoList = filesService.getFileInfoList(pageNo, pageSize);
        return RestResponseEntity.newResponseFromServiceResult(fileInfoList);
    }


    /**
     * 图片/pdf预览查看
     *
     * @param id 文件id
     * @return ResponseEntity响应体对象
     */
    // @GetMapping(value = "/view/{id}", produces = MediaType.IMAGE_PNG_VALUE)
    // 不能写死，否则预览pdf或者其它类型时，你还是返回png，导致报错
    @GetMapping("/view/{id}")
    public ResponseEntity<byte[]> viewImagePdfFiles(@PathVariable String id) throws IOException {
        // 通过id查找文件信息，然后获取后缀
        ServiceResult<FilesEntity> fileInfoById = filesService.getFileInfoById(id);
        // 拿到后缀
        String suffix = fileInfoById.getData().getSuffix();

        if (!fileInfoById.isSuccess()) {
            // 数据库找不到
            throw new SelfRuntimeException(ErrorCode.DATA_NOT_FOUND, "数据不存在！");
        }

        // 校验文件类型
        if (!FileConstant.PREVIEW_TYPES.contains(suffix)) {
            throw new SelfRuntimeException(ErrorCode.FILE_PREVIEW_ERROR, "该文件不支持预览，请下载查看！");
        }


        // 获取支持浏览器预览的文件类型，并构建头部信息
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(InputStreamUtils.getMediaType(suffix));

        // 获取文件输入流，然后通过输入流获取内存流
        InputStream inputStream = filesService.getFileInputStream(id);
        byte[] bytes = InputStreamUtils.inputStreamToByte(inputStream);

        // return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
        return ResponseEntity.ok()
                .headers(headers)
                .body(bytes);
    }


    /**
     * 文件下载
     *
     * @param id               文件id
     * @param isSourceFileName 是否使用原文件名；否 使用新文件名
     * @param request          请求
     * @param response         响应
     */
    @GetMapping("/download/{id}")
    public void fileDownload(@PathVariable String id, @RequestParam(required = false, defaultValue = "true") Boolean isSourceFileName,
                             HttpServletRequest request, HttpServletResponse response) {
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            // 去数据库查该文件id的信息
            ServiceResult<FilesEntity> fileInfoById = filesService.getFileInfoById(id);
            // 判断是否查询成功
            if (!fileInfoById.isSuccess()) {
                throw new SelfRuntimeException(ErrorCode.DATA_NOT_FOUND, "数据不存在！");
            }

            // 拿到文件名
            String fileName = isSourceFileName ? fileInfoById.getData().getFileName() : fileInfoById.getData().getFilePath();

            // 获取文件输入流
            inputStream = filesService.getFileInputStream(id);

            // 设置响应头：其中要设置对中文文件名的编码处理
            String encodingFileName = FileNameEncodingUtils.convertToFileName(fileName, request);
            response.setHeader("Content-Disposition", "attachment;filename=" + encodingFileName);

            // 获取文件输出流
            outputStream = response.getOutputStream();

            /*
            IOUtils.copy：就是实现流拷贝，将输入流拷贝到输出流中
            作用：把服务器的文件原样发送给浏览器，实现文件下载功能
            做什么：不停从inputStream读数据（文件内容） → 写到浏览器的outputStream
                   浏览器收到的就是文件内容 → 浏览器自动开始下载。
             */
            IOUtils.copy(inputStream, outputStream);
        } catch (Exception e) {
            log.error("文件下载出错", e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
